package myutil

import (
	"errors"
	"sync"
)

// Queue 并发安全的环形数组队列
type Queue[T any] struct {
	items    []T
	head     int
	tail     int
	size     int
	capacity int
	mutex    sync.RWMutex
	notEmpty *sync.Cond
	notFull  *sync.Cond
}

// NewQueue 创建并发安全的队列
func NewQueue[T any](capacity int) *Queue[T] {
	if capacity <= 0 {
		capacity = 10
	}
	queue := &Queue[T]{
		items:    make([]T, capacity),
		head:     0,
		tail:     0,
		size:     0,
		capacity: capacity,
	}
	queue.notEmpty = sync.NewCond(&queue.mutex)
	queue.notFull = sync.NewCond(&queue.mutex)
	return queue
}

// Push 将元素添加到队列尾部
// 阻塞模式时，不会返回error
func (q *Queue[T]) Push(item T, block bool) error {
	q.mutex.Lock()
	defer q.mutex.Unlock()

	if block { // 无限等待模式
		for q.size == q.capacity {
			q.notFull.Wait()
		}
	} else {
		if q.size == q.capacity {
			return errors.New("queue is full")
		}
	}

	q.items[q.tail] = item
	q.tail = (q.tail + 1) % q.capacity
	q.size++

	q.notEmpty.Signal() // 通知可能等待的出队操作

	return nil
}

// Pop 从队列头部移除元素
// 阻塞模式时，不会返回error
func (q *Queue[T]) Pop(block bool) (T, error) {
	q.mutex.Lock()
	defer q.mutex.Unlock()

	var zero T

	if block { // 无限等待模式
		for q.size == 0 {
			q.notEmpty.Wait()
		}
	} else {
		if q.size == 0 {
			return zero, errors.New("queue is empty")
		}
	}

	item := q.items[q.head]
	q.head = (q.head + 1) % q.capacity
	q.size--

	q.notFull.Signal()
	return item, nil
}

// Peek 查看队列头部元素但不移除
func (q *Queue[T]) Peek() (T, error) {
	q.mutex.RLock()
	defer q.mutex.RUnlock()

	var zero T
	if q.size == 0 {
		return zero, errors.New("queue is empty")
	}

	return q.items[q.head], nil
}

// IsEmpty 判断队列是否为空
func (q *Queue[T]) IsEmpty() bool {
	q.mutex.RLock()
	defer q.mutex.RUnlock()
	return q.size == 0
}

// IsFull 判断队列是否已满
func (q *Queue[T]) IsFull() bool {
	q.mutex.RLock()
	defer q.mutex.RUnlock()
	return q.size == q.capacity
}

// Size 获取队列当前长度
func (q *Queue[T]) Size() int {
	q.mutex.RLock()
	defer q.mutex.RUnlock()
	return q.size
}

// Capacity 获取队列容量
func (q *Queue[T]) Capacity() int {
	return q.capacity
}
